package battle

import (
	"kop/framework/errors"
	"kop/modules/configuration/configuration/attribute/attrtype"
	"kop/pb"
	"kop/util/rand"
	"math"
)

const (
	TargetTypeOur   = 1 // 我方
	TargetTypeOther = 2 // 对方
	TargetTypeSelf  = 3 // 自己
)

func Battle(t1, t2 []*pb.Captain) (*pb.PVPResp, error) {

	var resp pb.PVPResp

	var captains1, captains2 = make([]*pb.Captain, 0, len(t1)), make([]*pb.Captain, 0, len(t2))

	for _, v := range t1 {
		var attr = *v.Attribute
		var temp = *v
		temp.Attribute = &attr
		captains1 = append(captains1, &temp)
	}

	for _, v := range t2 {
		var attr = *v.Attribute
		var temp = *v
		temp.Attribute = &attr
		captains2 = append(captains2, &temp)
	}

	if len(captains1) == 0 || len(captains2) == 0 {
		return nil, errors.New("上阵船长数量为0")
	}

	var useSkill1 = true // 标识我方是否使用技能
	var useSkill2 = true // 标识敌方是否使用技能

	for {

		if len(captains1) == 0 {
			resp.Win = false
			break
		} else if len(captains2) == 0 {
			resp.Win = true
			break
		}

		var our = captains1[0]
		var other = captains2[0]

		if our.Attribute == nil {
			return nil, errors.ParamError
		}
		if other.Attribute == nil {
			return nil, errors.ParamError
		}

		var battleRes pb.Battle

		if useSkill1 && our.Skill1 != nil {
			// 我方使用技能
			switch our.Skill1.TargetType {
			case TargetTypeOther:
				// 敌方
				battleRes.Skill1 = useSkill(our.Skill1, captains2)
			default:
				// 我方
				battleRes.Skill1 = useSkill(our.Skill1, captains1)
			}
		}

		if useSkill2 && other.Skill1 != nil {
			// 敌方使用技能
			switch other.Skill1.TargetType {
			case TargetTypeOther:
				// 敌方攻击我方
				battleRes.Skill2 = useSkill(other.Skill1, captains1)
			default:
				// 敌方给自己加血
				battleRes.Skill2 = useSkill(other.Skill1, captains2)
			}
		}

		// 使用技能后的勇气和智力
		battleRes.SkillCOR1 = our.Attribute.COR
		battleRes.SkillCOR2 = other.Attribute.COR
		battleRes.INT1 = our.Attribute.INT
		battleRes.INT2 = other.Attribute.INT

		// 敌方受到的伤害 我方勇气 * 我方智力 / 敌方智力
		var damage1 = float64(our.Attribute.COR) * float64(our.Attribute.INT) / float64(other.Attribute.INT)

		// 我方受到的伤害 敌方勇气 * 敌方智力 / 我方智力
		var damage2 = float64(other.Attribute.COR) * float64(other.Attribute.INT) / float64(our.Attribute.INT)

		//********************************************** 对方受到的暴击 **********************************************/

		var CRTRate1 float32
		if our.Skill2 != nil {
			CRTRate1 = our.Skill2.CRTRate
		}

		if CRTRate1 > 0 && our.Skill3.CRTDamage > 0 && rand.IsWin(CRTRate1) {
			// 触发暴击
			damage1 = damage1 * (1 + float64(our.Skill3.CRTDamage))
			battleRes.Critical1 = true
		}

		//********************************************** 对方受到的暴击 **********************************************/
		//********************************************** 我方受到的暴击 **********************************************/

		var CRTRate2 float32
		if other.Skill2 != nil {
			CRTRate2 = other.Skill2.CRTRate
		}

		if CRTRate2 > 0 && other.Skill3.CRTDamage > 0 && rand.IsWin(CRTRate2) {
			// 触发暴击
			damage2 = damage2 * (1 + float64(other.Skill3.CRTDamage))
			battleRes.Critical2 = true
		}

		//********************************************** 我方受到的暴击 **********************************************/

		damage1 = math.Max(damage1, 1)
		damage2 = math.Max(damage2, 1)

		our.Attribute.COR -= int32(damage2)
		if our.Attribute.COR < 0 {
			our.Attribute.COR = 0
		}

		other.Attribute.COR -= int32(damage1)
		if other.Attribute.COR < 0 {
			other.Attribute.COR = 0
		}

		battleRes.P1 = int32(len(t1) - len(captains1))
		battleRes.P2 = int32(len(t2) - len(captains2))

		// 攻击之后的勇气和智力
		battleRes.COR1 = our.Attribute.COR
		battleRes.COR2 = other.Attribute.COR

		resp.Battle = append(resp.Battle, &battleRes)

		// 勇气为0就从切片里删除
		if our.Attribute.COR <= 0 {

			var newFighter1 = make([]*pb.Captain, 0)
			captains1 = append(newFighter1, captains1[1:]...)

			useSkill1 = true
		} else {
			useSkill1 = false
		}
		if other.Attribute.COR <= 0 {

			var newFighter2 = make([]*pb.Captain, 0)
			captains2 = append(newFighter2, captains2[1:]...)

			useSkill2 = true
		} else {
			useSkill2 = false
		}

	}

	return &resp, nil
}

func useSkill(skill *pb.CaptainSkill1, captains []*pb.Captain) *pb.BattleSkill {

	// 是否触发技能
	if rand.IsWin(skill.Rate) {

		var value float64

		var targetIndexes []int32
		if skill.TargetNumber == 0 {

			for i := 0; i < len(captains); i++ {
				targetIndexes = append(targetIndexes, int32(i))
			}
		} else {

			var values []rand.Value
			for k := range captains {
				values = append(values, rand.Struct{ID: int32(k), Weight: 1})
			}

			var res = rand.WithWeight(values, int(skill.TargetNumber))

			for _, v := range res {
				targetIndexes = append(targetIndexes, v.GetID())
			}
		}

		// 技能目标
		switch skill.TargetType {

		case TargetTypeOther:
			// 敌方

			value = 1 - float64(skill.Value)

		default:
			// 我方
			if skill.TargetType == TargetTypeSelf {
				// 对自己使用
				targetIndexes = []int32{0}
			}

			value = 1 + float64(skill.Value)
		}

		for _, v := range targetIndexes {

			switch attrtype.AttrType(skill.AttributeType) {
			case attrtype.TypeCOR:

				captains[v].Attribute.COR = int32(math.Max(1, value*float64(captains[v].Attribute.COR)))

			case attrtype.TypeINT:

				captains[v].Attribute.INT = int32(math.Max(1, value*float64(captains[v].Attribute.INT)))

			}
		}

		return &pb.BattleSkill{
			SkillID:       skill.SkillID,
			TargetType:    skill.TargetType,
			AttributeType: int32(attrtype.TypeINT),
			SkillTarget:   targetIndexes,
		}
	}
	return nil
}
